<template>
  <div class="app-container">
    <!-- 固定在顶部的步骤条和按钮组 -->
    <div class="fixed-header" style="z-index: 5">
      <el-steps
        class="steps-container"
        :space="200"
        :active="currentStep"
        simple
      >
        <el-step title="导入校正集" />
        <el-step title="主成分分析" />
        <el-step title="数据预处理参数设置" />
        <el-step title="波长选择参数设置" />
        <el-step title="训练模型参数设置" />
        <el-step title="保存模型" />
      </el-steps>

      <div class="button-group">
        <el-button
          type="primary"
          size="mini"
          @click="handleButtonClick(0, handleImportCalibration)"
          :disabled="!isStepAvailable(0)"
          >导入校正集</el-button
        >
        <el-button
          type="primary"
          size="mini"
          @click="handleButtonClick(1, handlePrincipalComponentAnalysis)"
          :disabled="!isStepAvailable(1)"
          >主成分分析</el-button
        >
        <el-button
          type="primary"
          size="mini"
          @click="handleButtonClick(2, handlePreProcess)"
          :disabled="!isStepAvailable(2)"
          >数据预处理参数</el-button
        >
        <el-button
          type="primary"
          size="mini"
          :disabled="!isStepAvailable(3)"
          @click="handleButtonClick(3, handleWaveLengthChoose)"
          >波长选择参数</el-button
        >
        <el-button
          type="primary"
          size="mini"
          @click="handleButtonClick(4, handleTraining)"
          :disabled="!isStepAvailable(4)"
          >训练模型</el-button
        >
        <el-button
          type="primary"
          size="mini"
          @click="handleButtonClick(5, handlePerformanceCharts)"
          :disabled="!isStepAvailable(5)"
          >训练过程评价指标</el-button
        >
        <el-button
          type="primary"
          size="mini"
          @click="handleButtonClick(5, saveModel)"
          :disabled="!isStepAvailable(5)"
          >保存模型</el-button
        >
        <!-- <el-button plain size="small" @click="closePage()">关闭</el-button> -->
      </div>
    </div>

    <!-- 可滚动的内容区域 -->
    <div class="content-area">
      <el-card shadow="always" style="padding: 20px">
        <el-row :gutter="20">
          <el-col :span="8">
            <stacked-line-chart
              v-if="seriesData1.length > 0"
              title="校正集吸光度曲线"
              :xAxisData="xAxisData1"
              :seriesData="seriesData1"
            />
            <div v-else class="empty-chart-placeholder">
              <div class="chart-title">校正集吸光度曲线</div>
              <div class="placeholder-content">
                <i class="el-icon-info"></i>
                <p>请先导入校正集</p>
              </div>
            </div>
          </el-col>
          <el-col :span="8" style="position: relative">
            <!-- 左上角悬浮按钮 -->
            <el-popover placement="bottom-end" width="220" trigger="click">
              <!-- 下拉选择框放在 Popover 内 -->
              <el-select
                v-model="selectedIteration"
                placeholder="请选择迭代次数"
                size="small"
                style="width: 200px"
              >
                <el-option
                  v-for="(item, index) in best_pre_data_history"
                  :key="index"
                  :label="'迭代次数 ' + (index + 1)"
                  :value="index"
                />
              </el-select>

              <!-- 触发按钮 + 悬浮提示 -->
              <template #reference>
                <el-tooltip content="选择迭代次数" placement="top">
                  <el-button
                    type="primary"
                    icon="el-icon-s-operation"
                    size="mini"
                    circle
                    style="
                      position: absolute;
                      top: 5px;
                      right: 15px;
                      z-index: 100;
                    "
                  />
                </el-tooltip>
              </template>
            </el-popover>
            <stacked-line-chart
              v-if="seriesData2.length > 0"
              title="预处理吸光度曲线"
              :xAxisData="xAxisData2"
              :seriesData="seriesData2"
            />
            <div v-else class="empty-chart-placeholder">
              <div class="chart-title">预处理吸光度曲线</div>
              <div class="placeholder-content">
                <i class="el-icon-info"></i>
                <p>请先完成数据预处理步骤</p>
              </div>
            </div>
          </el-col>
          <!-- <el-col :span="8">
            <stacked-line-chart
              v-if="seriesData3.length > 0"
              title="预测集吸光度曲线"
              :xAxisData="xAxisData3"
              :seriesData="seriesData3"
            />
          </el-col> -->
          <el-col :span="8" style="position: relative">
            <!-- 左上角悬浮按钮 -->
            <el-popover placement="bottom-end" width="220" trigger="click">
              <!-- 下拉选择框放在 Popover 内 -->
              <el-select
                v-model="waveSelectSelectedIteration"
                placeholder="请选择迭代次数"
                size="small"
                style="width: 200px"
              >
                <el-option
                  v-for="(item, index) in best_model_data_history"
                  :key="index"
                  :label="'迭代次数 ' + (index + 1)"
                  :value="index"
                />
              </el-select>

              <!-- 触发按钮 + 悬浮提示 -->
              <template #reference>
                <el-tooltip content="选择迭代次数" placement="top">
                  <el-button
                    type="primary"
                    icon="el-icon-s-operation"
                    size="mini"
                    circle
                    style="
                      position: absolute;
                      top: 5px;
                      right: 15px;
                      z-index: 100;
                    "
                  />
                </el-tooltip>
              </template>
            </el-popover>
            <wavelength-selection-chart
              v-if="chooseWavelength.length > 0"
              :fullSpectrumData="seriesData2"
              :fullXAxisData="xAxisData2"
              :selectedWavelengths="chooseWavelength"
              :sampleIndex="0"
            />

            <div v-else class="empty-chart-placeholder">
              <div class="chart-title">波长选择吸光度曲线</div>
              <div class="placeholder-content">
                <i class="el-icon-info"></i>
                <p>请先完成波长选择步骤</p>
              </div>
            </div>
          </el-col>
        </el-row>
      </el-card>

      <el-card shadow="always" style="padding: 20px; margin-top: 10px">
        <el-row :gutter="20" style="margin-top: 20px">
          <el-col :span="8">
            <scree-plot-chart
              v-if="screeX.length > 0"
              title="碎石图（Scree plot）"
              :screeX="screeX"
              :screeBar="screeBar"
              :screePlot="screePlot"
            />
            <div v-else class="empty-chart-placeholder">
              <div class="chart-title">碎石图（Scree plot）</div>
              <div class="placeholder-content">
                <i class="el-icon-info"></i>
                <p>请先完成主成分分析步骤</p>
              </div>
            </div>
          </el-col>
          <el-col :span="8">
            <stacked-line-chart
              v-if="seriesData5.length > 0"
              title="负载图（Loading plot）"
              :xAxisData="xAxisData5"
              :seriesData="seriesData5"
              :showLegend="true"
            />
            <div v-else class="empty-chart-placeholder">
              <div class="chart-title">负载图（Loading plot）</div>
              <div class="placeholder-content">
                <i class="el-icon-info"></i>
                <p>请先完成主成分分析步骤</p>
              </div>
            </div>
          </el-col>
          <el-col :span="8">
            <pca-scatter-chart
              v-if="scoreScatterPc1.length > 0"
              title="得分图（Score plot）"
              :scoreScatterPc1="scoreScatterPc1"
              :scoreScatterPc2="scoreScatterPc2"
              :pc1Value="pc1Value"
              :pc2Value="pc2Value"
              :ellipseAngle="ellipseAngle"
              :ellipseWidth="ellipseWidth"
              :ellipseHeight="ellipseHeight"
            />
            <div v-else class="empty-chart-placeholder">
              <div class="chart-title">得分图（Score plot）</div>
              <div class="placeholder-content">
                <i class="el-icon-info"></i>
                <p>请先完成主成分分析步骤</p>
              </div>
            </div>
          </el-col>
        </el-row>
      </el-card>

      <el-card shadow="always" style="padding: 2px; margin-top: 10px">
        <el-row :gutter="20" style="margin-top: 20px" height="300px">
          <el-col :span="24">
            <el-table
              ref="modelDetailTable"
              :data="modelDetailtableData"
              border
              style="width: 100%"
              max-height="300"
              :header-cell-style="{ textAlign: 'center' }"
              :cell-style="{ textAlign: 'center' }"
              @selection-change="handleModelDetailSelection"
              highlight-current-row
            >
              <el-table-column
                type="selection"
                width="55"
                align="center"
              ></el-table-column>
              <!-- <el-table-column
              prop="modelNo" 
              label="模型详情编号"
              :show-overflow-tooltip="true"
            ></el-table-column> -->
              <el-table-column label="进化迭代数" align="center" width="120px">
                <template slot-scope="scope">
                  {{ scope.$index + 1 }}
                </template>
              </el-table-column>
              <el-table-column
                width="120px"
                prop="n_components"
                label="潜在变量数"
                align="center"
              >
              </el-table-column>
              <el-table-column
                prop="preProcess"
                label="预处理方法"
                :show-overflow-tooltip="true"
                align="center"
              >
              </el-table-column>
              <el-table-column
                width="130px"
                prop="waveSelect"
                label="波长选择方法"
                :show-overflow-tooltip="true"
                align="center"
              >
              </el-table-column>
              <el-table-column
                width="120px"
                prop="rc2"
                label="Rc²"
                :formatter="formatNumber"
              ></el-table-column>
              <el-table-column
                width="120px"
                prop="rmsecv"
                label="RMSECV"
                :formatter="formatNumber"
              ></el-table-column>
              <el-table-column
                width="120px"
                prop="rp2"
                label="Rp²"
                :formatter="formatNumber"
              ></el-table-column>
              <el-table-column
                width="120px"
                prop="rmsep"
                label="RMSEP"
                :formatter="formatNumber"
              ></el-table-column>
              <el-table-column
                width="120px"
                prop="rpd"
                label="RPD"
                :formatter="formatNumber"
              ></el-table-column>
              <el-table-column
                width="120px"
                prop="t_value"
                :label="tTestColumnLabel"
                :formatter="formatNumber"
              ></el-table-column>
              <el-table-column label="操作" align="center" width="120">
                <template slot-scope="scope">
                  <span
                    class="correlation-link"
                    @click="showCorrelationChart(scope.row, scope.$index + 1)"
                  >
                    相关性图
                  </span>
                </template>
              </el-table-column>
            </el-table>
          </el-col>
          <!-- <el-col :span="8">
            <model-evaluation-chart
              title="模型评价曲线"
              :modelDetailData="modelDetailtableData"
            />
          </el-col> -->
        </el-row>
      </el-card>

      <el-dialog
        title="导入校正集"
        ref="modelDataDialog"
        :visible.sync="calibrationdialogVisible"
        width="80vw"
        height="50vh"
        append-to-body
      >
        <model-data
          ref="constructTable"
          :is-row-visible="false"
          @selection-change="handleCalibrationSelection"
          style="height: 100%; overflow-y: scroll"
        />
        <div slot="footer" class="dialog-footer">
          <el-button type="primary" @click="getCalibration">确 认</el-button>
          <el-button @click="calibrationdialogVisible = false">取 消</el-button>
        </div>
      </el-dialog>

      <!-- 预处理方法选择框 -->
      <el-dialog
        title="设置预处理方法参数"
        :visible.sync="preProcessdialogVisible"
        width="60vw"
        append-to-body
      >
        <el-table
          ref="preProcessMethod"
          :data="methodList"
          border
          style="width: 100%"
          row-key="code"
        >
          <!-- 拖动 -->
          <!-- <el-table-column label="拖动" width="60" align="center">
            <template slot-scope="scope">
              <div
                draggable="true"
                @dragstart="handleDragStart(scope.$index)"
                @dragover.prevent
                @drop="handleDrop(scope.$index)"
                style="cursor: move"
              >
                <i class="el-icon-rank"></i>
              </div>
            </template>
          </el-table-column> -->

          <!-- 启用 -->
          <el-table-column label="启用" width="60" align="center">
            <template slot-scope="scope">
              <el-checkbox v-model="scope.row.enabled" />
            </template>
          </el-table-column>

          <!-- 顺序 -->
          <!-- <el-table-column label="顺序" width="80" align="center">
            <template slot-scope="scope">
              <span v-if="scope.row.enabled">
                {{
                  methodList
                    .filter((item) => item.enabled)
                    .findIndex((item) => item.code === scope.row.code) + 1
                }}
              </span>
            </template>
          </el-table-column> -->
          <!-- 基本信息 -->
          <!-- <el-table-column prop="code" label="代码" align="center" width="80" /> -->
          <el-table-column prop="name" label="名称" align="center" />

          <!-- 参数1 -->
          <el-table-column label="窗口" width="100" align="center">
            <template slot-scope="scope">
              <el-input
                v-if="needsParam(scope.row.code)"
                v-model="scope.row.param1"
                size="mini"
                placeholder="窗口"
              />
            </template>
          </el-table-column>

          <!-- 参数2 -->
          <el-table-column label="阶数" width="100" align="center">
            <template slot-scope="scope">
              <el-input
                v-if="needsParam(scope.row.code)"
                v-model="scope.row.param2"
                size="mini"
                placeholder="阶数"
              />
            </template>
          </el-table-column>
        </el-table>
        <div slot="footer" class="dialog-footer">
          <el-button type="primary" @click="preProcessing">确 认</el-button>
          <el-button @click="preProcessdialogVisible = false">取 消</el-button>
        </div>
      </el-dialog>

      <!-- 波长选择方法设置框 -->
      <el-dialog
        title="波长选择方法参数设置"
        :visible.sync="wavelengthChooseVisible"
        width="80vw"
        append-to-body
      >
        <el-table :data="wavelengthChooseList" border style="width: 100%">
          <!-- 启用 -->
          <el-table-column label="启用" width="60" align="center">
            <template slot-scope="scope">
              <el-checkbox v-model="scope.row.enabled" />
            </template>
          </el-table-column>

          <!-- 名称 -->
          <el-table-column prop="name" label="名称" align="center" />

          <!-- 设置参数1 -->
          <el-table-column label="设置参数1" width="120" align="center">
            <template slot-scope="scope">
              <el-input
                v-if="scope.row.paramLabels[0]"
                v-model="scope.row.params[0]"
                :placeholder="scope.row.paramLabels[0]"
                size="mini"
              />
            </template>
          </el-table-column>

          <!-- 设置参数2 -->
          <el-table-column label="设置参数2" width="120" align="center">
            <template slot-scope="scope">
              <el-input
                v-if="scope.row.paramLabels[1]"
                v-model="scope.row.params[1]"
                :placeholder="scope.row.paramLabels[1]"
                size="mini"
              />
            </template>
          </el-table-column>

          <!-- 设置参数3 -->
          <el-table-column label="设置参数3" width="120" align="center">
            <template slot-scope="scope">
              <el-input
                v-if="scope.row.paramLabels[2]"
                v-model="scope.row.params[2]"
                :placeholder="scope.row.paramLabels[2]"
                size="mini"
              />
            </template>
          </el-table-column>
        </el-table>

        <div slot="footer" class="dialog-footer">
          <el-button type="primary" @click="handleWavelengthSelection"
            >确 认</el-button
          >
          <el-button @click="wavelengthChooseVisible = false">取 消</el-button>
        </div>
      </el-dialog>

      <!-- 训练参数设置对话框 -->
      <el-dialog
        title="训练参数设置"
        :visible.sync="trainingParamsVisible"
        width="480px"
        append-to-body
      >
        <el-form :model="trainingParams" label-width="160px">
          <!-- 交叉验证比例 -->
          <el-form-item label="交叉验证比例">
            <el-select
              v-model="trainingParams.crossValidationRatio"
              placeholder="请选择比例"
              style="width: 120px"
            >
              <el-option label="2:1" value="0.3"></el-option>
              <el-option label="3:1" value="0.4"></el-option>
              <el-option label="4:1" value="0.5"></el-option>
            </el-select>
          </el-form-item>

          <!-- 最大潜在变量数 -->
          <el-form-item label="最大潜在变量数">
            <el-input-number
              v-model="trainingParams.maxLatentVariables"
              :min="1"
              :max="20"
              controls-position="right"
              style="width: 120px"
            />
          </el-form-item>

          <!-- 遗传算法参数 - 迭代数 -->
          <el-form-item label="迭代数">
            <el-input-number
              v-model="trainingParams.iterations"
              :min="0"
              :max="20"
              :default-value="10"
              controls-position="right"
              style="width: 120px"
            />
          </el-form-item>

          <!-- 遗传算法参数 - 每代个体数 -->
          <el-form-item label="每代个体数">
            <el-input-number
              v-model="trainingParams.populationSize"
              :min="0"
              :max="10"
              :default-value="10"
              controls-position="right"
              style="width: 120px"
            />
          </el-form-item>

          <!-- 遗传算法参数 - 变异率 -->
          <el-form-item label="变异率">
            <el-input-number
              v-model="trainingParams.mutationRate"
              :min="0"
              :max="1"
              :step="0.01"
              :default-value="0.1"
              controls-position="right"
              style="width: 120px"
            />
          </el-form-item>
        </el-form>

        <!-- 底部按钮 -->
        <div slot="footer" class="dialog-footer" style="text-align: right">
          <el-button @click="trainingParamsVisible = false">取 消</el-button>
          <el-button type="primary" @click="confirmTraining"
            >开始训练</el-button
          >
          <el-tooltip
            content="训练过程可能需要1-2分钟，请耐心等待"
            placement="top"
          >
            <i
              class="el-icon-info"
              style="margin-left: 5px; color: #909399"
            ></i>
          </el-tooltip>
        </div>
      </el-dialog>
    </div>
    <el-dialog
      ref="modelTrainProcessMetrics"
      :visible.sync="performanceChartsVisible"
      width="80vw"
      top="5vh"
      append-to-body
      custom-class="performance-dialog"
      title="训练过程评价曲线"
    >
      <div class="dialog-content-wrapper">
        <PerformanceCharts
          :avg-perf-history="avgPerfHistory"
          :best-perf-history="bestPerfHistory"
        />
      </div>
    </el-dialog>

    <!-- 相关性图对话框 -->
    <el-dialog
      title="相关性图信息"
      :visible.sync="correlationDialogVisible"
      width="80%"
      append-to-body
    >
      <div v-if="currentRowData">
        <!-- 相关性散点图 -->
        <div style="margin-bottom: 20px">
          <div ref="correlationChart" style="width: 100%; height: 400px"></div>
        </div>
      </div>

      <div slot="footer" class="dialog-footer">
        <el-button @click="correlationDialogVisible = false">关闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import StackedLineChart from "@/views/tool/build/ChartComponent.vue"; // 路径根据项目调整
import ModelData from "@/views/model/construct/index.vue";
import PcaScatterChart from "@/components/PcaScatterChart.vue";
import ScreePlotChart from "@/components/ScreePlotChart.vue";
import WavelengthSelectionChart from "@/components/WavelengthSelectionChart.vue";
import PerformanceCharts from "@/components/PerformanceCharts .vue";
import ModelEvaluationChart from "@/components/ModelEvaluationChart.vue";
import {
  saveModelData,
  delModelDetailData,
  getModelDetailData,
  updateData as updateModelData,
} from "@/api/model/data";
import { addModelDetail } from "@/api/model/modelDetail";
import { addPreprocessing } from "@/api/model/preprocessing";
import { addWaveSelect } from "@/api/model/waveSelect";
import { listConstructDetail } from "@/api/model/constructDetail";
import draggable from "vuedraggable";
import axios from "axios";
import * as echarts from "echarts";

export default {
  components: {
    StackedLineChart,
    ModelData,
    draggable,
    PcaScatterChart,
    ScreePlotChart,
    WavelengthSelectionChart,
    ModelEvaluationChart,
    PerformanceCharts,
  },
  data() {
    return {
      // 根据选中的模型详情进化迭代数，进行预处理参数和波长选择参数的存储
      iterations: 0,
      best_pre_data_history: [], // 假设从接口或其他地方获取的数组
      best_model_data_history: [],
      best_combination_history: [],
      selectedIteration: 0, // 默认选中第一个迭代次数（索引 0）
      waveSelectSelectedIteration: 0,
      // 步骤完成状态
      stepCompleted: [false, false, false, false, false, false], // 对应6个步骤的完成状态
      // 模型详情
      modelDetail_data: {},
      // 预处理过程信息
      preProcessing_data: {},
      // 波长选择信息
      waveSelect_data: {},
      modelData: null,
      trainPayload: {
        // 校正集的原始吸光度曲线
        train_x: [],

        // 训练集的标准值
        train_y: [],

        // 验证集的原始吸光度曲线
        test_x: [],

        // 验证集的标准值
        test_y: [],

        // 验证集的预处理方法及过程参数
        // 与预处理过程的区别：部分方法需要之前预处理得到的过程参数（可能有或无）
        // 除过程参数外，与原preprocessing_sequence结构一致
        vail_pre_sequence: [], // 修正：应该是数组，包含多个预处理方法对象

        // 波长选择的索引
        // selected_indices: [],
        wave_select: [],

        // 最大潜在变量数（最大主成分数）   测试合并 test fenzhi he master fenzhi
        max_components: 0,

        // 交叉验证折数
        // 转换规则：2:1→3折、3:1→4折、4:1→5折
        cv_folds: 0,

        n_samples: 0,
        n_generations: 0,
        mutation_rate: 0,
      },
      train_result: null,
      critical_t: null, // 存储临界t值
      currentStep: 0, // 当前步骤索引
      standardValueList: [], // 标准值存储列表
      preProcessing_result: null, // 预处理结果
      selected_indices: null, // 存储选择的波长索引
      startWavelength: 0, // 起始波长
      endWavelength: 0,
      mask: null, // 掩码
      modelNo: "",
      modelId: "", // 模型ID
      pca_req: null,
      // PCA相关数据
      scoreScatterPc1: [],
      scoreScatterPc2: [],
      pc1Value: 0,
      pc2Value: 0,
      // 椭圆参数
      ellipseAngle: 0,
      ellipseWidth: 0,
      ellipseHeight: 0,
      // 碎石图数据
      screeX: [],
      screeBar: [],
      screePlot: [],
      modelDetailtableData: [],
      selectedModelDetail: null, // 存储选中的模型详情数据
      dragStartIndex: null,
      preProcessing_waveData: [],
      selectedConstructData: null, // 用于存储选中的建模数据行
      chooseWavelength: [], // 存储选中的波长点
      calibrationdialogVisible: false,
      preProcessdialogVisible: false,
      wavelengthChooseVisible: false,
      trainingParamsVisible: false,
      performanceChartsVisible: false,
      // 相关性图对话框相关变量
      correlationDialogVisible: false,
      currentRowData: null,
      currentLatentVariableCount: 0,
      correlationChartInstance: null,
      trainingParams: {
        crossValidationRatio: "0.3", // 默认2:1
        maxLatentVariables: 3, // 默认5个潜在变量
        iterations: 10, // 遗传算法迭代数，默认10
        populationSize: 10, // 每代个体数，默认10
        mutationRate: 0.1, // 变异率，默认0.1
      },
      avgPerfHistory: [],
      bestPerfHistory: [],
      xAxisData1: [],
      xAxisData2: [],
      xAxisData3: [],
      xAxisData4: [],
      xAxisData5: [],
      xAxisData6: [],
      seriesData1: [],
      seriesData2: [],
      seriesData3: [],
      seriesData4: [],
      seriesData5: [],
      seriesData6: [],
      preProcessingPayload: {
        // 预处理方法序列
        preprocessing_sequence: [],
        // 预处理波长数据
        wave_data: [],
      },
      methodList: [
        {
          code: "01",
          type: "baseline",
          name: "差分一阶导",
          e_Name: "diff_derivative",
          enabled: true,
        },
        {
          code: "02",
          type: "baseline",
          name: "差分二阶导",
          e_Name: "diff_derivative",
          enabled: true,
        },
        {
          code: "03",
          type: "baseline",
          name: "SG一阶导",
          e_Name: "sg_derivative",
          enabled: true,
          param1: "5",
          param2: "3",
        },
        {
          code: "04",
          type: "baseline",
          name: "SG二阶导",
          e_Name: "sg_derivative",
          enabled: true,
          param1: "5",
          param2: "3",
        },
        {
          code: "05",
          type: "scatter",
          name: "标准正交变量（SNV）",
          e_Name: "snv",
          enabled: true,
        },
        {
          code: "06",
          type: "scatter",
          name: "多元散射校正（MSC）",
          e_Name: "msc",
          enabled: true,
        },
        {
          code: "07",
          name: "SG平滑处理",
          e_Name: "sg_smoothing",
          type: "smoothing",
          enabled: true,
          param1: "5",
          param2: "3",
        },
        {
          code: "08",
          type: "scaling",
          name: "均值中心化",
          e_Name: "centering",
          enabled: true,
        },
        {
          code: "09",
          type: "scaling",
          name: "归一化",
          e_Name: "normalization",
          enabled: true,
        },
        {
          code: "10",
          type: "scaling",
          name: "标准化",
          e_Name: "standardization",
          enabled: true,
        },
      ],
      wavelengthChooseList: [
        {
          code: "01",
          name: "无信息变量消除（VUE）",
          method: "VUE",
          enabled: true,
          params: ["20", "10", ""],
          paramLabels: ["特征数", "迭代数", ""],
        },
        {
          code: "02",
          name: "相关系数法",
          method: "CORRELATION",
          enabled: true,
          params: ["0", "", ""],
          paramLabels: ["阈值", "", ""],
        },
        {
          code: "03",
          method: "SPA",
          name: "连续投影算法（SPA）",
          enabled: true,
          params: ["10", "", ""],
          paramLabels: ["特征数", "", ""],
        },
        // {
        //   code: "04",
        //   name: "竞争性自适应加权采样（CARS）",
        //   method: "CARS",
        //   enabled: true,
        //   params: ["3", "3", ""],
        //   paramLabels: ["特征数", "迭代数", ""],
        // },
        {
          code: "05",
          name: "变量投影重要性（VIP）",
          method: "VIPSelection",
          enabled: true,
          params: ["10", "", ""],
          paramLabels: ["特征数", "", ""],
        },
        {
          code: "06",
          name: "区间组合偏最小二乘法（siPLS）",
          method: "SiPLS",
          enabled: true,
          params: ["10", "3", "3"],
          paramLabels: ["迭代数", "变量数", "成分数"],
        },
      ],
    };
  },
  computed: {
    // sortedMethodList() {
    //   return [...this.methodList].sort((a, b) => {
    //     // enabled true 的排前面
    //     if (a.enabled === b.enabled) return 0;
    //     return a.enabled ? -1 : 1;
    //   });
    // },
    getCurrentSeriesData() {
      // 根据选中的迭代次数，从 best_pre_data_history 取对应 train_X_pre
      console.log("getCurrentSeriesData", selectedItem.train_X_pre);
      const selectedItem = this.best_pre_data_history[this.selectedIteration];
      return selectedItem ? selectedItem.train_X_pre : [];
    },
    // 动态生成t检验列头标签
    tTestColumnLabel() {
      if (this.critical_t !== null) {
        return `t检验（${this.critical_t}）`;
      }
      return "t检验";
    },
  },
  watch: {
    // 监听对话框显示状态
    correlationDialogVisible(newVal) {
      if (newVal) {
        // 对话框打开时，延迟初始化图表
        this.$nextTick(() => {
          setTimeout(() => {
            this.initCorrelationChart();
          }, 100);
        });
      } else {
        // 对话框关闭时，销毁图表
        this.destroyCorrelationChart();
      }
    },
    // 监听 best_pre_data_history 变化，比如数据初始化后，确保下拉有数据
    best_pre_data_history(newVal) {
      if (newVal.length > 0 && this.selectedIteration >= newVal.length) {
        this.selectedIteration = 0;
      }
    },
    // 监听选中项变化，可在这里做额外逻辑，比如打印日志、触发接口等
    selectedIteration() {
      // 也可以直接在这里重新处理 xAxisData2 等，根据实际数据关联情况调整
      console.log("ceshi", this.best_pre_data_history);
      const chooseData =
        this.best_pre_data_history[this.selectedIteration].train_X_pre;
      // return selectedItem ? selectedItem.train_X_pre : [];
      this.drawPreprocessingCurve(chooseData);
      console.log("切换了迭代次数，当前选中：", this.selectedIteration);
    },
    waveSelectSelectedIteration() {
      // 也可以直接在这里重新处理 xAxisData2 等，根据实际数据关联情况调整
      console.log("ceshi", this.best_model_data_history);
      const selectedIndices =
        this.best_model_data_history[this.waveSelectSelectedIteration]
          .selected_indices;

      // 将索引转换为实际的波长值
      this.chooseWavelength = this.convertIndicesToWavelengths(selectedIndices);

      console.log(
        "切换了迭代次数，当前选中：",
        this.waveSelectSelectedIteration,
        "选中的波长:",
        this.chooseWavelength
      );
    },
  },
  mounted() {
    window.addEventListener("beforeunload", this.handleBeforeUnload);
    this.modelNo = this.$route.query.modelNo || "";
    this.modelId = this.$route.query.modelId || "";
    console.log("接收到的参数：", this.modelNo);
    console.log("接收到的参数：", this.modelId);
    // 初始化时绑定启用变化监听
    this.watchMethodChange();
  },

  beforeDestroy() {
    window.removeEventListener("beforeunload", this.handleBeforeUnload);
    // 清理相关性图表实例
    this.destroyCorrelationChart();
  },
  beforeRouteLeave(to, from, next) {
    // 检查是否有未保存的数据
    const hasUnsavedData = this.currentStep > 0 && this.currentStep < 6;

    if (hasUnsavedData) {
      // 使用同步的confirm，可以立即阻止路由跳转
      const confirmed = window.confirm(
        "关闭页面将丢失当前页面的修改，是否关闭？"
      );
      if (confirmed) {
        next(); // 用户确认，允许跳转
      } else {
        next(false); // 用户取消，阻止跳转
      }
    } else {
      next(); // 无需提示，直接放行
    }
  },
  methods: {
    // 检查步骤是否可用
    isStepAvailable(stepIndex) {
      // 第一步（导入校正集）始终可用
      if (stepIndex === 0) return true;

      // 其他步骤需要前一步完成
      return this.stepCompleted[stepIndex - 1];
    },

    // 统一的按钮点击处理
    handleButtonClick(stepIndex, callback) {
      // 检查是否是逆序操作
      if (this.isReverseOperation(stepIndex)) {
        this.showReverseWarning(stepIndex, callback);
        return;
      }

      // 正常执行操作
      callback();
    },

    // 检查是否是逆序操作
    isReverseOperation(stepIndex) {
      // 如果当前步骤之后有已完成的步骤，则认为是逆序操作
      for (let i = stepIndex + 1; i < this.stepCompleted.length; i++) {
        if (this.stepCompleted[i]) {
          return true;
        }
      }
      return false;
    },
    handlePerformanceCharts() {
      this.performanceChartsVisible = true;
      this.avgPerfHistory = this.train_result.result.avg_perf_history;
      this.bestPerfHistory = this.train_result.result.best_perf_history;
    },

    // 显示逆序操作警告
    showReverseWarning(stepIndex, callback) {
      const stepNames = [
        "导入校正集",
        "主成分分析",
        "数据预处理参数设置",
        "波长选择参数设置",
        "训练模型参数设置",
        "保存模型",
      ];

      this.$confirm(
        `重新执行"${stepNames[stepIndex]}"将会清空后续所有步骤的数据和结果，包括图表显示、参数设置等。您确定要继续吗？`,
        "逆序操作警告",
        {
          confirmButtonText: "确定继续",
          cancelButtonText: "取消",
          type: "warning",
          dangerouslyUseHTMLString: true,
        }
      )
        .then(() => {
          // 用户确认后，清空后续步骤的数据
          this.clearSubsequentSteps(stepIndex);
          // 执行操作
          callback();
        })
        .catch(() => {
          // 用户取消，不执行任何操作
        });
    },

    // 清空后续步骤的数据
    clearSubsequentSteps(fromStep) {
      // 清空后续步骤的完成状态
      for (let i = fromStep; i < this.stepCompleted.length; i++) {
        this.stepCompleted[i] = false;
      }

      // 根据步骤清空相应的数据
      if (fromStep <= 0) {
        // 清空校正集相关数据
        this.seriesData1 = [];
        this.xAxisData1 = [];
        this.standardValueList = [];
        this.selectedConstructData = null;
        this.preProcessing_waveData = [];
      }

      if (fromStep <= 1) {
        // 清空预处理相关数据
        this.seriesData2 = [];
        this.xAxisData2 = [];
        this.preProcessing_result = null;
        this.preProcessingPayload = {};
      }

      if (fromStep <= 2) {
        // 清空波长选择相关数据
        this.chooseWavelength = [];
        this.selected_indices = null;
        this.mask = null;
        this.waveSelect_data = {};
      }

      if (fromStep <= 3) {
        // 清空主成分分析相关数据
        this.scoreScatterPc1 = [];
        this.scoreScatterPc2 = [];
        this.pc1Value = 0;
        this.pc2Value = 0;
        this.ellipseAngle = 0;
        this.ellipseWidth = 0;
        this.ellipseHeight = 0;
        this.screeX = [];
        this.screeBar = [];
        this.screePlot = [];
        this.seriesData5 = [];
        this.xAxisData5 = [];
      }

      if (fromStep <= 4) {
        // 清空训练相关数据
        this.modelDetailtableData = [];
        this.selectedModelDetail = null;
        this.train_result = null;
        this.critical_t = null;
      }

      // 重置当前步骤
      this.currentStep = fromStep;
    },

    handleBeforeUnload(event) {
      // 自定义提示内容，部分浏览器会忽略这段内容，但仍会弹出默认提示框
      event.preventDefault();
      event.returnValue = "您确定要离开此页面吗？所有未保存的数据将会丢失。";
    },
    closePage() {
      this.$confirm(
        "您确定要离开此页面吗？所有未保存的数据将会丢失。",
        "提示",
        {
          confirmButtonText: "确认",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(() => {
          const visitedViews = this.$store.state.tagsView.visitedViews;
          const currentPath = this.$route.fullPath;

          const index = visitedViews.findIndex(
            (view) => view.fullPath === currentPath
          );

          // 找到要跳转的下一个页面
          const nextView = visitedViews[index - 1] ||
            visitedViews[index + 1] || { path: "/" };

          // 删除当前页面标签并跳转
          this.$store
            .dispatch("tagsView/delVisitedView", this.$route)
            .then(() => {
              this.$router.push(nextView.path);
            });
        })
        .catch(() => {
          // 用户点击“取消”，不做任何处理
        });
    },
    // 处理模型详情表格选择变化
    handleModelDetailSelection(selection) {
      // 限制只能选择一行
      if (selection.length > 1) {
        const lastSelected = selection[selection.length - 1];
        this.$nextTick(() => {
          this.$refs.modelDetailTable.clearSelection();
          this.$refs.modelDetailTable.toggleRowSelection(lastSelected, true);
        });
        this.selectedModelDetail = lastSelected;
      } else {
        this.selectedModelDetail = selection[0] || null;
      }

      if (this.selectedModelDetail) {
        console.log("选中的模型详情:", this.selectedModelDetail);
        console.log("迭代次数:", this.selectedModelDetail.indexLabel);
        this.iterations =  this.selectedModelDetail.indexLabel
      }
    },
    async saveModel() {
      if (!this.selectedModelDetail) {
        this.$message.warning("请先选择要保存的模型详情");
        return;
      }

      // 根据preprocessing_sequence获取预处理方法名称
      const preMethodName = this.selectedModelDetail.preProcess;

      // 获取波长选择方法名称
      const waveSelectMethodName = this.selectedModelDetail.waveSelect;

      // 构建模型数据对象
      const rc2 = Number(this.selectedModelDetail.rc2);

      this.modelData = {
        modelId: parseInt(this.modelId) || this.modelId, // 确保是数字类型
        modelNo: this.modelNo, // 模型编号
        // modelStateCode: "02",
        // modelStateName: "已完成",
        cv_ratio_name: this.trainingParams.crossValidationRatio, // 使用下划线命名
        preMethodName: preMethodName, // 使用下划线命名
        waveSelectMethodName: waveSelectMethodName, // 使用下划线命名
        maxPotential: Number(this.selectedModelDetail.latentVariableCount) || 0, // 使用下划线命名
        rc2: Number(this.selectedModelDetail.rc2) || 0.0,
        rmsecv: Number(this.selectedModelDetail.rmsecv) || 0.0,
        rp2: Number(this.selectedModelDetail.rp2) || 0.0,
        rmsep: Number(this.selectedModelDetail.rmsep) || 0.0,
        rpd: Number(this.selectedModelDetail.rpd) || 0.0,
        tTest: Number(this.selectedModelDetail.t_value) || 0.0, // 使用下划线命名
                // 添加 constructNo 和 samplingTime 字段
        constructNo: this.selectedConstructData ? this.selectedConstructData.constructNo : null,
        samplingTime: this.selectedConstructData ? this.selectedConstructData.samplingTime : null,
      };

      // 数据验证
      if (!this.modelNo) {
        this.$message.error("模型编号不能为空");
        return;
      }

      if (!preMethodName) {
        this.$message.warning("请先完成数据预处理步骤");
        return;
      }

      if (!waveSelectMethodName) {
        this.$message.warning("请先完成波长选择步骤");
        return;
      }

      try {
        const res = await updateModelData(this.modelData);

        if (res && res.code === 200) {
          this.$message.success("模型详情保存成功");
          this.currentStep = 6; // 更新到完成步骤
          this.stepCompleted[5] = true; // 标记保存模型步骤完成
          console.log("✅ 模型保存成功，步骤更新为:", this.currentStep);
        } else {
          const errorMsg = res?.message || res?.msg || "未知错误";
          console.error("❌ 保存失败，后端返回:", res);
          this.$message.error("模型详情保存失败：" + errorMsg);
        }
      } catch (error) {
        console.error("❌ 保存模型数据时发生错误:", error);
        console.error("❌ 错误详情:", {
          message: error.message,
          response: error.response,
          request: error.request,
        });

        let errorMessage = "保存失败：";
        if (error.response && error.response.data) {
          errorMessage +=
            error.response.data.message ||
            error.response.data.msg ||
            error.response.statusText;
        } else {
          errorMessage += error.message || error.toString();
        }

        this.$message.error(errorMessage);
      }

      this.$message({
        message: `已选择模型详情：潜在变量数${this.selectedModelDetail.latentVariableCount}，准备保存...`,
        type: "success",
      });

      // 1、保存预处理过程信息
      await this.savePreprocessingData();

      // 2、保存波长选择信息
      await this.saveWaveSelectData();

      // 3、保存模型详情数据
      await this.saveModelDetailData();

      // 3、取消模型详情被选中的那行
      this.selectedModelDetail = null;
      this.$refs.modelDetailTable.clearSelection();
    },

    /**
     * 加载模型详情，并赋值到表格数据中
     * @param {Array<Object>} dataArray – 后端返回的模型性能指标数组
     */
    loadModelDetails(
      dataArray,
      best_combination_history,
      best_model_data_history
    ) {
      if (!Array.isArray(dataArray)) {
        console.warn("loadModelDetails 的参数不是数组，请检查");
        return;
      }

      // 若需要更改"潜在变量数"（n_components）到表中，可追加字段：
      const formatted = dataArray.map((item, index) => ({
        ...item,
        latentComponents: item.n_components,
        latentVariableCount: item.n_components, // 添加这个字段映射，用于图表组件
        indexLabel: index + 1, // 备用：方便调试或展示
      }));

      // 假设这是从best_combination_history提取的信息
      best_combination_history.forEach((combination, index) => {
        // 提取preprocess并映射到methodList中的name
        const preprocessMethods = combination.preprocess
          .map((item) => {
            const methodEntry = this.methodList.find(
              (m) => m.e_Name === item[1].method
            );
            return methodEntry ? methodEntry.name : item[1].method; // 如果找不到匹配项，返回原始method
          })
          .join(", "); // 拼接成字符串

        // 提取wave_select并映射到wavelengthChooseList中的name
        const waveSelectMethod =
          this.wavelengthChooseList.find(
            (w) => w.method === combination.wave_select.method
          )?.name || combination.wave_select.method; // 如果找不到匹配项，返回原始method

        // 将提取的信息添加到formatted中
        if (formatted[index]) {
          formatted[index].preProcess = preprocessMethods;
          formatted[index].waveSelect = waveSelectMethod;
        }
      });

      best_model_data_history.forEach((modelData, index) => {
        // 检查 modelData 和 coef 是否存在
        if (modelData && modelData.coef && Array.isArray(modelData.coef)) {
          const coef = modelData.coef
            .map((item) => {
              // 确保 item 结构正确
              if (item && item.length > 1 && item[1] && item[1].method) {
                const methodEntry = this.methodList.find(
                  (m) => m.e_Name === item[1].method
                );
                return methodEntry ? methodEntry.name : item[1].method; // 如果找不到匹配项，返回原始method
              }
              return ""; // 如果数据结构不正确，返回空字符串
            })
            .filter((name) => name !== "") // 过滤掉空字符串
            .join(", "); // 拼接成字符串

          // 将提取的信息添加到formatted中
          if (formatted[index]) {
            formatted[index].coef = coef;
          }
        } else {
          // 如果 coef 数据不存在或格式不正确，设置为空字符串
          if (formatted[index]) {
            formatted[index].coef = "";
          }
        }
      });

      // 赋值给 Table 的数据源
      this.modelDetailtableData = formatted;
    },

    // 根据preprocessing_sequence获取预处理方法名称
    getPreprocessingMethodNames() {
      if (
        !this.preProcessingPayload ||
        !this.preProcessingPayload.preprocessing_sequence
      ) {
        return "";
      }

      const methodNames = [];

      // 遍历预处理序列
      this.preProcessingPayload.preprocessing_sequence.forEach((item) => {
        if (item.root && item.root.method) {
          // 在methodList中查找对应的方法名称
          const method = this.methodList.find(
            (m) => m.e_Name === item.root.method
          );
          if (method) {
            methodNames.push(method.name);
          }
        }
      });

      // 用 " + " 连接方法名称
      return methodNames.join(" , ");
    },

    // 获取波长选择方法名称
    getWavelengthSelectionMethodName() {
      // 查找当前启用的波长选择方法
      const selectedMethod = this.wavelengthChooseList.find(
        (item) => item.enabled
      );
      return selectedMethod ? selectedMethod.name : "";
    },

    // 保存预处理过程数据, 从best_pre_data_history中获取
    async savePreprocessingData() {
      try {
        // 添加判空逻辑
        if (
          !this.best_pre_data_history ||
          this.best_pre_data_history.length === 0 ||
          this.iterations <= 0
        ) {
          console.warn("预处理数据不存在或迭代次数无效，跳过保存");
          return;
        }

        // 检查索引是否有效
        if (this.iterations > this.best_pre_data_history.length) {
          console.warn(
            `迭代索引 ${this.iterations} 超出数组范围 ${this.best_pre_data_history.length}`
          );
          return;
        }
        console.log("保存预处理数据...", this.best_pre_data_history);
        console.log("保存预处理数据...", this.best_combination_history);
        console.log("保存预处理数据...", this.iterations);
        // 保存预处理数据和预处理序列
        const preprocessData = JSON.parse(
          JSON.stringify(this.best_pre_data_history[this.iterations - 1])
        );
        delete preprocessData.train_X_pre;
        delete preprocessData.val_X_pre;

        const preprocessResult = JSON.stringify(preprocessData);
        const preprocessSequence = JSON.stringify(
          this.best_combination_history[this.iterations - 1].preprocess
        );

        // 构建预处理数据对象
        this.preProcessing_data = {
          modelId: parseInt(this.modelId) || this.modelId,
          datasetId: this.selectedConstructData?.constructId || null,
          preprocessingSequence: preprocessSequence,
          preprocessingResult: preprocessResult,
        };

        console.log("🚀 准备保存预处理数据:", this.preProcessing_data);

        // 调用API保存预处理数据
        const response = await addPreprocessing(this.preProcessing_data);

        if (response && response.code === 200) {
          console.log("✅ 预处理数据保存成功");
          this.$message.success("预处理过程信息保存成功");
        } else {
          console.error("❌ 预处理数据保存失败:", response);
          this.$message.warning(
            "预处理过程信息保存失败：" +
              (response?.message || response?.msg || "未知错误")
          );
        }
      } catch (error) {
        console.error("❌ 保存预处理数据时发生错误:", error);
        this.$message.warning(
          "预处理过程信息保存失败：" + (error.message || error.toString())
        );
      }
    },

    // 保存波长选择数据
    async saveWaveSelectData() {
      try {
        // 检查必要的数据是否存在
        if (!this.best_combination_history || !this.best_model_data_history) {
          console.warn("波长选择历史数据不存在，跳过保存");
          return;
        }
        
        // 检查迭代次数是否有效
        if (!this.iterations || this.iterations <= 0) {
          console.warn("迭代次数无效，跳过保存");
          return;
        }
        
        // 检查索引是否在范围内
        if (this.iterations > this.best_combination_history.length || 
            this.iterations > this.best_model_data_history.length) {
          console.warn(`迭代索引 ${this.iterations} 超出数组范围，跳过保存`);
          return;
        }
        
        // 检查波长选择数据和选中索引是否存在
        const waveSelectData = this.best_combination_history[this.iterations - 1]?.wave_select;
        const selectedIndices = this.best_model_data_history[this.iterations - 1]?.selected_indices;
        
        if (!waveSelectData || !selectedIndices) {
          console.warn("波长选择数据或选中索引不存在，跳过保存");
          return;
        }

        // 构建波长选择数据对象
        const waveSelectSaveData = {
          modelId: parseInt(this.modelId) || this.modelId,
          datasetId: this.selectedConstructData?.constructId || null,
          waveSelect: JSON.stringify(waveSelectData),
          selected_indices: JSON.stringify(selectedIndices)
        };

        console.log("🚀 准备保存波长选择数据:", waveSelectSaveData);

        // 调用API保存波长选择数据
        const response = await addWaveSelect(waveSelectSaveData);

        if (response && response.code === 200) {
          console.log("✅ 波长选择数据保存成功");
          this.$message.success("波长选择信息保存成功");
        } else {
          console.error("❌ 波长选择数据保存失败:", response);
          this.$message.warning(
            "波长选择信息保存失败：" +
              (response?.message || response?.msg || "未知错误")
          );
        }
      } catch (error) {
        console.error("❌ 保存波长选择数据时发生错误:", error);
        this.$message.warning(
          "波长选择信息保存失败：" + (error.message || error.toString())
        );
      }
    },

    formatNumber(row, column, cellValue) {
      if (typeof cellValue === "number") {
        return cellValue.toFixed(4);
      }
      return cellValue;
    },

    // 调试方法：直接测试预处理数据保存
    async debugSavePreprocessing() {
      console.log("🔧 开始调试预处理数据保存功能...");

      // 模拟预处理数据，用于调试
      this.preProcessing_result = {
        X_preprocessed: [
          [1, 2, 3],
          [4, 5, 6],
        ], // 这个不会被保存
        x_center_mean: [0.1, 0.2, 0.3],
        x_msc_mean: [0.4, 0.5, 0.6],
        x_standar_mean: [0.7, 0.8, 0.9],
        x_standar_scale: [1.0, 1.1, 1.2],
        x_nor_max: [2.0, 2.1, 2.2],
        x_nor_min: [0.01, 0.02, 0.03],
      };

      // 模拟预处理方法序列
      this.preProcessingPayload = {
        preprocessing_sequence: [
          {
            root: {
              type: "baseline",
              method: "diff_derivative",
              params: { deriv_order: 1 },
            },
          },
          {
            root: {
              type: "scaling",
              method: "centering",
            },
          },
        ],
      };

      // 模拟选中的建模数据
      this.selectedConstructData = {
        constructId: 1,
      };

      console.log("🔧 模拟数据已设置:");
      console.log("  - preProcessing_result:", this.preProcessing_result);
      console.log("  - preProcessingPayload:", this.preProcessingPayload);
      console.log("  - selectedConstructData:", this.selectedConstructData);
      console.log("  - modelId:", this.modelId);

      // 调用保存方法
      await this.savePreprocessingData();

      console.log("🔧 调试完成！");
    },

    // 调试方法：直接测试波长选择数据保存
    async debugSaveWaveSelect() {
      console.log("🔧 开始调试波长选择数据保存功能...");

      // 模拟波长选择数据，用于调试
      this.waveSelect_data = [
        {
          root: {
            method: "SiPLS",
            params: {
              n_intervals: 3,
              n_select: 2,
              n_components: 2,
            },
          },
        },
      ];

      // 模拟选择的波长索引
      this.selected_indices = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];

      // 模拟掩码
      this.mask = [
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
      ];

      // 模拟选择的波长点
      this.chooseWavelength = [
        "400",
        "402",
        "404",
        "406",
        "408",
        "410",
        "412",
        "414",
        "416",
        "418",
      ];

      // 模拟选中的建模数据
      this.selectedConstructData = {
        constructId: 1,
      };

      console.log("🔧 模拟数据已设置:");
      console.log("  - waveSelect_data:", this.waveSelect_data);
      console.log("  - selected_indices:", this.selected_indices);
      console.log("  - mask:", this.mask);
      console.log("  - chooseWavelength:", this.chooseWavelength);
      console.log("  - selectedConstructData:", this.selectedConstructData);
      console.log("  - modelId:", this.modelId);

      // 调用保存方法
      await this.saveWaveSelectData();

      console.log("🔧 调试完成！");
    },
    handleTraining() {
      // 检查是否已完成前面的步骤
      // if (!this.mask || !this.selected_indices) {
      //   this.$message.warning("请先完成波长选择步骤");
      //   return;
      // }

      // 显示训练参数设置对话框
      this.trainingParamsVisible = true;
    },

    // 减少潜在变量数
    decreaseLatentVariables() {
      if (this.trainingParams.maxLatentVariables > 1) {
        this.trainingParams.maxLatentVariables--;
      }
    },

    // 增加潜在变量数
    increaseLatentVariables() {
      if (this.trainingParams.maxLatentVariables < 20) {
        this.trainingParams.maxLatentVariables++;
      }
    },

    // 确认训练参数并开始训练
    async confirmTraining() {
      try {
        // 根据交叉验证比例计算折数
        const ratio = parseFloat(this.trainingParams.crossValidationRatio);
        let cvFolds;
        if (ratio === 0.3) cvFolds = 3;
        else if (ratio === 0.4) cvFolds = 4;
        else if (ratio === 0.5) cvFolds = 5;
        else cvFolds = 5; // 默认5折

        // 收集验证集数据
        let validationData = [];
        let validationStandardValues = [];

        try {
          const validationResponse = await listConstructDetail({
            constructNo: this.selectedConstructData.constructNo,
            constructdTypeName: "验证集",
            pageNum: 1,
            pageSize: 9999, // 设置一个足够大的数值
          });

          if (
            validationResponse.code === 200 &&
            validationResponse.rows.length > 0
          ) {
            console.log("验证集数据：", validationResponse.rows);

            // 仿照校正集的逻辑，处理验证集数据
            validationData = validationResponse.rows.map((row) => {
              const wavelengthArray = row.wavelength.split(",").map(Number);
              const standardValue = Number(row.standard);
              validationStandardValues.push(standardValue);

              // 返回波长数据（不包含标准值，因为标准值单独存储）
              return wavelengthArray;
            });

            console.log("处理后的验证集光谱数据:", validationData);
            console.log("验证集标准值:", validationStandardValues);
          } else {
            console.log("未找到验证集数据或验证集为空");
          }
        } catch (validationError) {
          console.warn("获取验证集数据失败:", validationError);
        }
        this.trainPayload.n_samples = this.trainingParams.populationSize;
        this.trainPayload.n_generations = this.trainingParams.iterations;
        this.trainPayload.mutation_rate = this.trainingParams.mutationRate;
        this.trainPayload.test_x = validationData;
        this.trainPayload.test_y = validationStandardValues;
        this.trainPayload.train_y = this.standardValueList;
        this.trainPayload.vail_pre_sequence = this.methodList
          .filter((item) => item.enabled)
          .map((item) => {
            const payload = this.buildMethodPayload(item, true);
            console.log(
              `验证集预处理方法 ${item.name}:`,
              JSON.stringify(payload, null, 2)
            );
            return payload;
          });

        this.trainPayload.max_components =
          this.trainingParams.maxLatentVariables;
        this.trainPayload.cv_folds = cvFolds;
        console.log("训练请求数据this.trainPayload:", this.trainPayload);
        this.trainingParamsVisible = false;
        const trainingMessage = this.$message({
          message: "模型训练中，请稍候...",
          type: "info",
          duration: 0, // 0表示不自动关闭
          showClose: true,
          offset: 100, // 调整距离顶部的距离，实现右上角效果
        });

        // const response = await axios.post(
        //   "/train-model/auto-train",
        //   this.trainPayload
        // );
        const response = await axios.get("/mock/api-train-response.json");
        console.log("训练结果:", response.data);
        this.train_result = response.data;
        this.best_pre_data_history = response.data.result.best_pre_data_history;
        this.best_model_data_history =
          response.data.result.best_model_data_history;
        this.best_combination_history =
          response.data.result.best_combination_history;

        // 绘制预处理吸光度曲线，只需要找到最大迭代次数的就行
        const preprocessedData =
          response.data.result.best_pre_data_history[
            this.trainingParams.iterations - 1
          ].train_X_pre;
        this.drawPreprocessingCurve(preprocessedData);
        const selectedIndices =
          response.data.result.best_model_data_history[
            this.trainingParams.iterations - 1
          ].selected_indices;
        // 将索引转换为实际的波长值
        this.chooseWavelength =
          this.convertIndicesToWavelengths(selectedIndices);
        this.waveSelectSelectedIteration = this.trainingParams.iterations - 1;
        this.loadModelDetails(
          response.data.result.best_perf_history,
          response.data.result.best_combination_history,
          response.data.result.best_model_data_history
        );
        console.log("选择波长索引:", selectedIndices);
        console.log("选择波长值:", this.chooseWavelength);
        // 绘制潜在变量数表格
        // 绘制模型评价曲线
        // 绘制

        // 关闭训练中提示并显示成功信息
        trainingMessage.close();
        this.$message({
          message:
            '<i class="el-icon-success el-icon--right"></i> 模型训练完成',
          type: "success",
          offset: 50,
          duration: 5000,
        });
        console.log("模型详情数据lalallaa:", response);

        this.trainingParamsVisible = false;
        this.$message.success("模型训练完成");
        this.currentStep = 5; // 更新到保存模型步骤
        this.stepCompleted[4] = true; // 标记训练模型步骤完成
        this.trainingParamsVisible = false;
      } catch (error) {
        console.error("模型训练失败:", error);
        this.$message.error(
          "模型训练失败: " + (error.response?.data?.message || error.message)
        );
      }
    },
    drawPreprocessingCurve(result) {
      if (!result || !Array.isArray(result)) {
        console.warn("预处理数据格式不正确");
        return;
      }

      const newSeries = [];
      let xAxisSet = new Set();

      // 假设result是一个二维数组，每个元素是一个样本的吸光度数据
      result.forEach((sampleData, index) => {
        if (Array.isArray(sampleData) && sampleData.length > 0) {
          // 生成X轴数据（波长）
          const xAxis = sampleData.map((_, i) =>
            (this.startWavelength + i).toString()
          );
          xAxis.forEach((w) => xAxisSet.add(w));

          newSeries.push({
            name: `样本 ${index + 1}`,
            type: "line",
            data: sampleData,
            smooth: true,
            lineStyle: {
              width: 1.5,
            },
            itemStyle: {
              opacity: 0.7,
            },
          });
        }
      });

      this.seriesData2 = newSeries;
      this.xAxisData2 = Array.from(xAxisSet).sort(
        (a, b) => Number(a) - Number(b)
      );

      this.selectedIteration = this.trainingParams.iterations - 1;

      console.log("预处理吸光度曲线数据已更新:", {
        seriesCount: newSeries.length,
        xAxisLength: this.xAxisData2.length,
        startWavelength: this.startWavelength,
        endWavelength: this.startWavelength + this.xAxisData2.length - 1,
      });
    },

    parseTrainingResponse(response) {
      // 基础校验
      if (!response || !response.data || !response.data.data) {
        throw new Error("无效的响应格式：缺少核心数据字段");
      }

      const rawData = response.data.data;
      const result = {
        // 基础信息
        status: rawData.status,
        executionTime: rawData.execution_time,

        // 训练历史数据（数组形式保持原样，但字段标准化）
        history: {
          bestCombinations: rawData.result?.best_combination_history || [],
          bestPerformances: rawData.result?.best_perf_history || [],
          avgPerformances: rawData.result?.avg_perf_history || [],
          modelDatas: rawData.result?.best_model_data_history || [],
          preprocessedDatas: rawData.result?.best_pre_data_history || [],
        },

        // 提取最终最优结果（取最后一次迭代的数据）
        finalResult: {},
      };

      // 计算迭代次数
      const iterationCount = result.history.bestCombinations.length;

      // 提取最后一次迭代的最优结果（如果有数据）
      if (iterationCount > 0) {
        const lastIndex = iterationCount - 1;

        result.finalResult = {
          combination: result.history.bestCombinations[lastIndex],
          performance: result.history.bestPerformances[lastIndex],
          modelData: result.history.modelDatas[lastIndex],
          preprocessedData: result.history.preprocessedDatas[lastIndex],
        };
      }

      // 性能指标格式化（保留4位小数）
      if (result.finalResult.performance) {
        const perf = result.finalResult.performance;
        Object.keys(perf).forEach((key) => {
          if (typeof perf[key] === "number") {
            perf[key] = Number(perf[key].toFixed(4));
          }
        });
      }

      return result;
    },

    addModelDetail() {
      const modelList = [
        {
          modelNo: this.modelNo,
          latentVariableCount: 10,
          rc2: 0.95,
          rmsecv: 0.12,
          rp2: 0.94,
          rmsep: 0.15,
          rpd: 2.1,
          t_value: 5.32,
          t: 1.98,
          calibrationStandard: [1.1, 2.2, 3.3],
          calibrationPredicted: [1.0, 2.1, 3.2],
          validationPredicted: [1.2, 2.3, 3.4],
          coef: [0.1, 0.2, 0.3],
        },
        {
          modelNo: this.modelNo,
          latentVariableCount: 8,
          rc2: 0.92,
          rmsecv: 0.2,
          rp2: 0.91,
          rmsep: 0.18,
          rpd: 1.9,
          t_value: 4.87,
          t: 1.96,
          calibrationStandard: [2.1, 3.2, 4.3],
          calibrationPredicted: [2.0, 3.1, 4.2],
          validationPredicted: [2.2, 3.3, 4.4],
          coef: [0.15, 0.25, 0.35],
        },
      ];
      this.modelDetailtableData = modelList; // 将数据存储到模型明细表中
      saveModelData(modelList).then((res) => {
        if (res.code === 200) {
          this.$message({
            message: "模型训练成功",
            type: "success",
          });
        } else {
          this.$message({
            message: "模型训练失败",
            type: "error",
          });
        }
      });
    },
    getModelDetail() {
      getModelDetailData(this.modelNo).then((res) => {
        if (res) {
          console.log("模型明细数据：", res.data);
          this.$message({
            message: "模型明细查询成功",
            type: "success",
          });
        } else {
          this.$message({
            message: "模型明细查询失败或无数据",
            type: "error",
          });
        }
      });
    },
    deleteModelDetail() {
      delModelDetailData(this.modelNo).then((res) => {
        if (res.code === 200) {
          this.$message({
            message: "模型明细删除成功",
            type: "success",
          });
          // this.modelDetailtableData = []; // 清空表格数据
        } else {
          this.$message({
            message: "模型明细删除失败",
            type: "error",
          });
        }
      });
    },
    async handlePrincipalComponentAnalysis() {
      // 检查是否已完成波长选择
      // if (!this.mask || !this.selected_indices) {
      //   this.$message.warning("请先完成波长选择步骤");
      //   return;
      // }

      try {
        // 构建PCA请求数据 - 使用波长选择后的数据
        const pcaPayload = {
          wave_data: this.preProcessing_waveData,
        };

        console.log("PCA请求数据:", pcaPayload);

        const pca_result = await axios.post("/train-model/pca", pcaPayload);
        console.log("PCA结果:", pca_result.data);

        // 更新组件数据
        this.scoreScatterPc1 = pca_result.data.result.score_scatter_pc1;
        this.scoreScatterPc2 = pca_result.data.result.score_scatter_pc2;
        this.pc1Value = pca_result.data.result.pc1_values * 100;
        this.pc2Value = pca_result.data.result.pc2_values * 100;

        // 更新椭圆参数
        this.ellipseAngle = pca_result.data.result.angle || 0;
        this.ellipseWidth = pca_result.data.result.width || 0;
        this.ellipseHeight = pca_result.data.result.height || 0;

        console.log("PCA散点图数据已更新:", {
          pc1: this.scoreScatterPc1,
          pc2: this.scoreScatterPc2,
          pc1Value: this.pc1Value,
          pc2Value: this.pc2Value,
        });

        // 更新负载图数据
        const loadings_pc1 = pca_result.data.result.loadings_scatter_pc1 || [];
        const loadings_pc2 = pca_result.data.result.loadings_scatter_pc2 || [];

        // 为负载图生成X轴数据（通常是波长索引或特征索引）
        this.xAxisData5 = loadings_pc1.map((_, index) =>
          (index + 1).toString()
        );

        // 为负载图生成系列数据
        this.seriesData5 = [
          {
            name: "PC1",
            type: "line",
            data: loadings_pc1,
            lineStyle: {
              color: "#FF4444",
              width: 2,
            },
            itemStyle: {
              color: "#FF4444",
            },
          },
          {
            name: "PC2",
            type: "line",
            data: loadings_pc2,
            lineStyle: {
              color: "#00AA00",
              width: 2,
            },
            itemStyle: {
              color: "#00AA00",
            },
          },
        ];

        console.log("负载图数据已更新:", {
          xAxisData5: this.xAxisData5,
          seriesData5: this.seriesData5,
        });

        // 更新碎石图数据
        this.screeX = pca_result.data.result.scree_x || [];
        this.screeBar = pca_result.data.result.scree_bar || [];
        this.screePlot = pca_result.data.result.scree_plot || [];

        console.log("碎石图数据已更新:", {
          screeX: this.screeX,
          screeBar: this.screeBar,
          screePlot: this.screePlot,
        });

        this.$message.success("主成分分析完成");
        this.currentStep = 1; // 更新到训练模型步骤
        this.stepCompleted[1] = true; // 标记主成分分析步骤完成
      } catch (error) {
        console.error("PCA分析失败:", error);
        this.$message.error(
          "主成分分析失败: " + (error.response?.data?.message || error.message)
        );
      }
    },
    handleSingleSelect(selectedIndex) {
      this.wavelengthChooseList.forEach((item, index) => {
        item.enabled = index === selectedIndex;
      });
    },
    async saveModelDetailData() {
      if (!this.modelDetail_data) {
        this.modelDetail_data = {};
      }

      // 1. 碎石图 screePlot
      this.modelDetail_data.screePlot = JSON.stringify({
        x: this.screeX,
        bar: this.screeBar,
        line: this.screePlot,
      });

      // 2. 负载图 loadingPlot
      this.modelDetail_data.loadingPlot = JSON.stringify({
        xAxis: this.xAxisData5,
        series: this.seriesData5,
      });

      // 3. 得分图 scorePlot
      this.modelDetail_data.scorePlot = JSON.stringify({
        pc1: this.scoreScatterPc1,
        pc2: this.scoreScatterPc2,
        pc1Value: this.pc1Value,
        pc2Value: this.pc2Value,
        ellipseAngle: this.ellipseAngle,
        ellipseWidth: this.ellipseWidth,
        ellipseHeight: this.ellipseHeight,
      });
      this.modelDetail_data.modelId = parseInt(this.modelId) || this.modelId;
      this.modelDetail_data.modelNo = this.modelNo || "";
      this.modelDetail_data.constituentId =
        this.selectedModelDetail.constituentId || 0;
      this.modelDetail_data.coef =
        JSON.stringify(this.selectedModelDetail.coef) || "";
      this.modelDetail_data.intercept = this.selectedModelDetail.intercept || 0;

      this.modelDetail_data.startWavelength = this.startWavelength;
      this.modelDetail_data.endWavelength = this.endWavelength;

      addModelDetail(this.modelDetail_data).then((res) => {
        if (res.code === 200) {
          this.$message({
            message: "模型明细保存成功",
            type: "success",
          });
        } else {
          this.$message({
            message: "模型明细保存失败",
            type: "error",
          });
        }
      });
    },
    handleWaveLengthChoose() {
      this.wavelengthChooseVisible = true;
    },
    preProcessing() {
      const enabledMethods = this.methodList.filter((item) => item.enabled);

      if (enabledMethods.length === 0) {
        this.$message.warning("请至少选择一种预处理方法");
        return;
      }

      // 校验参数
      for (const item of enabledMethods) {
        if (this.needsParam(item.code)) {
          if (!item.param1 || !item.param2) {
            this.$message.error(`方法「${item.name}」参数不能为空`);
            return;
          }
        }
      }

      // 构造最终结构（预处理时不包含过程参数）
      const preprocessing_sequence = enabledMethods.map((item) =>
        this.buildMethodPayload(item, false)
      );

      console.log(
        "🚀 最终 preprocessing_sequence:",
        JSON.stringify({ preprocessing_sequence }, null, 2)
      );

      // 模拟预处理结果 - 这里应该调用后端API
      // this.simulatePreprocessingResult();

      this.$message.success("预处理参数设置完成");
      this.currentStep = 2; // 更新到波长选择步骤
      this.stepCompleted[2] = true; // 标记数据预处理步骤完成
      this.preProcessdialogVisible = false;
    },

    handleDragStart(index) {
      this.dragStartIndex = index;
    },
    handleDrop(dropIndex) {
      const item = this.methodList[this.dragStartIndex];
      this.methodList.splice(this.dragStartIndex, 1);
      this.methodList.splice(dropIndex, 0, item);
    },
    // 监听 checkbox 状态改变
    watchMethodChange() {
      this.methodList.forEach((item) => {
        this.$watch(
          () => item.enabled,
          (newVal) => {
            if (newVal) {
              const payload = this.buildMethodPayload(item);
              console.log("✅ 启用方法:", JSON.stringify(payload, null, 2));
            }
          }
        );
      });
    },
    buildMethodPayload(item, includeProcessParams = false) {
      const payload = {
        root: {
          type: item.type, // 如 scaling、smoothing、baseline
          method: item.e_Name, // 如 normalization、sg_smoothing
        },
      };

      // 处理用户输入参数（预处理前确定的参数）
      if (this.needsParam(item.code)) {
        payload.root.params = {
          window: Number(item.param1),
          polyorder: Number(item.param2),
        };

        // SG导数需要额外的导数阶数参数
        if (item.code === "03" || item.code === "04") {
          payload.root.params.deriv_order = item.code === "03" ? 1 : 2;
        }
      }

      // 差分导数只需要导数阶数参数
      if (item.code === "01" || item.code === "02") {
        payload.root.params = {
          deriv_order: item.code === "01" ? 1 : 2,
        };
      }

      // 如果需要包含过程参数（用于验证集预处理）
      if (includeProcessParams && this.preProcessing_result) {
        if (!payload.root.params) {
          payload.root.params = {};
        }

        // 根据方法类型添加对应的过程参数
        switch (item.code) {
          case "05": // SNV - 通常不需要过程参数
            break;
          case "06": // MSC
            if (this.preProcessing_result.x_msc_mean) {
              console.log(
                "MSC x_mean:",
                JSON.stringify(this.preProcessing_result.x_msc_mean, null, 2)
              );
              payload.root.params.x_mean = this.preProcessing_result.x_msc_mean;
            }
            break;
          case "08": // 均值中心化
            if (this.preProcessing_result.x_center_mean) {
              console.log(
                "Center x_mean:",
                JSON.stringify(
                  this.preProcessing_result.x_center_mean[0],
                  null,
                  2
                )
              );
              payload.root.params.x_mean =
                this.preProcessing_result.x_center_mean[0];
            }
            break;
          case "09": // 归一化
            if (
              this.preProcessing_result.x_nor_max &&
              this.preProcessing_result.x_nor_min
            ) {
              payload.root.params.data_max =
                this.preProcessing_result.x_nor_max;
              payload.root.params.data_min =
                this.preProcessing_result.x_nor_min;
            }
            break;
          case "10": // 标准化
            if (
              this.preProcessing_result.x_standar_mean &&
              this.preProcessing_result.x_standar_scale
            ) {
              payload.root.params.x_mean =
                this.preProcessing_result.x_standar_mean;
              payload.root.params.scale =
                this.preProcessing_result.x_standar_scale;
            }
            break;
        }
      }

      return payload;
    },
    // 判断是否需要参数
    needsParam(code) {
      return ["03", "04", "07"].includes(code);
    },

    // 构建波长选择参数
    buildWaveSelectParams(selectedMethod) {
      const params = {};

      // 根据不同的方法构建不同的参数结构
      switch (selectedMethod.method) {
        case "SiPLS":
          params.n_intervals = Number(selectedMethod.params[0]) || 3;
          params.n_select = Number(selectedMethod.params[1]) || 2;
          params.n_components = Number(selectedMethod.params[2]) || 2;
          break;
        case "VUE":
          params.n_features = Number(selectedMethod.params[0]) || 20;
          params.n_iter = Number(selectedMethod.params[1]) || 10;
          break;
        case "CORRELATION":
          params.threshold = Number(selectedMethod.params[0]) || 0;
          break;
        case "CARS":
          params.n_features = Number(selectedMethod.params[0]) || 20;
          params.n_iter = Number(selectedMethod.params[1]) || 10;
          break;
        case "VIPSelection":
          params.n_features = Number(selectedMethod.params[0]) || 20;
          break;
        case "SPA":
          params.n_features = Number(selectedMethod.params[0]) || 20;
          break;
        default:
          // 默认情况下，将非空参数按顺序添加
          selectedMethod.params.forEach((param, index) => {
            if (param && param.trim() !== "") {
              params[`param${index + 1}`] = isNaN(param)
                ? param
                : Number(param);
            }
          });
      }

      return params;
    },
    handlePreProcess() {
      this.preProcessdialogVisible = true;
    },
    getCalibration() {
      if (!this.selectedConstructData) {
        this.$message({
          message: "请先选择校正集数据",
          type: "warning",
        });
        return;
      }
      listConstructDetail({
        constructNo: this.selectedConstructData.constructNo,
        constructdTypeName: "校正集",
        pageNum: 1,
        pageSize: 9999, // 设置一个足够大的数值
      }).then((res) => {
        if (res.code === 200 && res.rows.length > 0) {
          // this.modelDetailtableData = res.rows;
          console.log("校正集数据：", res);
          console.log("校正集数据：", res.rows);
          // 设置训练时携带的校正集原始吸光度曲线
          this.trainPayload.train_x = res.rows.map((row) =>
            row.wavelength.split(",").map(Number)
          );
          // 处理校正集数据，将standard和wavelength数据组合成一个数组
          this.preProcessing_waveData = res.rows.map((row) => {
            const wavelengthArray = row.wavelength.split(",").map(Number);
            const standardValue = Number(row.standard);
            this.standardValueList.push(standardValue);
            console.log("this.standardValueList:", this.standardValueList);
            // 将标准值和波长数据合并成一个数组：[标准值, 波长1, 波长2, ...]
            return [standardValue, ...wavelengthArray];
          });

          console.log("处理后的数据格式:", this.preProcessing_waveData);
          // 根据建模数据编号到建模明细表查询出校正集
          this.$message({
            message: `已选择校正集数据：${this.selectedConstructData.constructNo}`,
            type: "success",
          });

          this.currentStep = 1; // 更新步骤到数据预处理
          this.stepCompleted[0] = true; // 标记导入校正集步骤完成
          this.calibrationdialogVisible = false; // 关闭对话框

          const newSeries = [];
          let xAxisSet = new Set();

          for (const row of res.rows) {
            const start = Number(row.startWavelength);
            const end = Number(row.endWavelength);
            const waveStr = row.wavelength;
            const waveArr = waveStr.split(",").map(Number);

            // 使用 this.startWavelength 作为X轴起点
            const x = Array.from({ length: end - start }, (_, i) =>
              (this.startWavelength + i).toString()
            );
            x.forEach((w) => xAxisSet.add(w));

            newSeries.push({
              name: row.constructDetailNo,
              type: "line",
              data: waveArr,
            });
          }

          this.seriesData1 = newSeries;
          this.xAxisData1 = Array.from(xAxisSet).sort((a, b) => a - b);
          // this.startWavelength  应该作为x轴的起点
          console.log("seriesData1", this.seriesData1);
          console.log("xAxisData1", this.xAxisData1);
        } else {
          this.$message({
            message: "校正集数据加载失败",
            type: "error",
          });
        }
      });
      listConstructDetail({
        constructNo: this.selectedConstructData.constructNo,
        constructdTypeName: "验证集",
        pageNum: 1,
        pageSize: 9999, // 设置一个足够大的数值
      }).then((res) => {
        if (res.code === 200 && res.rows.length > 0) {
          this.trainPayload.test_x = res.rows.map((row) =>
            row.wavelength.split(",").map(Number)
          );
          this.trainPayload.test_y = res.rows.map((row) => row.standard);
          console.log("this.trainPayload收集验证集数据:", this.trainPayload);
        } else {
          this.$message({
            message: "验证集数据加载失败",
            type: "error",
          });
        }
      });
    },
    handleCalibrationSelection(selection) {
      const constructTableRef = this.$refs.constructTable.$refs.constructTable;
      if (selection.length > 1) {
        const lastSelected = selection[selection.length - 1];
        this.$nextTick(() => {
          constructTableRef.clearSelection(); // 清除所有选中
          constructTableRef.toggleRowSelection(lastSelected, true); // 仅保留当前选中
        });
        this.selectedConstructData = lastSelected;
      } else {
        this.selectedConstructData = selection[0] || null;
      }
      this.startWavelength = this.selectedConstructData
        ? this.selectedConstructData.startWavelength
        : 0;
      this.endWavelength = this.selectedConstructData
        ? this.selectedConstructData.endWavelength
        : 0;
      console.log("查看选中的建模数据信息", this.selectedConstructData);
    },
    chooseCalibration() {
      this.calibrationdialogVisible = false;
      // 这里可以添加处理选择校正集的逻辑
      this.$message({
        message: "校正集已选择",
        type: "success",
      });
    },
    handleImportCalibration() {
      this.calibrationdialogVisible = true;
    },
    loadAllCharts() {
      // 示例：这里你可以调用各自的 API 或函数分别填充数据
      this.xAxisData1 = this.genXAxis();
      this.seriesData1 = [
        { name: "A", data: [7.6, 7.5, 7.7, 7.8, 7.81, 7.9, 8.25] },
      ];

      this.xAxisData2 = this.genXAxis();
      this.seriesData2 = [
        { name: "B", data: [7.5, 7.4, 7.6, 7.85, 7.9, 8.0, 8.2] },
      ];

      this.xAxisData3 = this.genXAxis();
      this.seriesData3 = [
        { name: "C", data: [7.4, 7.3, 7.5, 7.7, 7.8, 8.0, 8.3] },
      ];

      this.xAxisData4 = this.genXAxis();
      this.seriesData4 = [
        { name: "Scree", data: [7.3, 7.2, 7.6, 7.8, 7.85, 8.0, 8.2] },
      ];

      this.xAxisData5 = this.genXAxis();
      this.seriesData5 = [
        { name: "Load", data: [7.5, 7.3, 7.6, 7.85, 7.95, 8.1, 8.25] },
      ];

      this.xAxisData6 = this.genXAxis();
      this.seriesData6 = [
        { name: "Score", data: [7.6, 7.5, 7.7, 7.8, 7.9, 8.1, 8.3] },
      ];
    },

    // 将索引数组转换为实际的波长值数组
    convertIndicesToWavelengths(indices) {
      if (!indices || !Array.isArray(indices)) {
        console.warn("索引数据无效:", indices);
        return [];
      }

      if (!this.xAxisData2 || this.xAxisData2.length === 0) {
        console.warn("没有可用的波长轴数据 (xAxisData2)");
        // 如果没有预处理的X轴数据，根据startWavelength生成
        return indices.map((index) =>
          (this.startWavelength + index).toString()
        );
      }

      // 根据索引从 xAxisData2 中获取对应的波长值
      const wavelengths = indices
        .filter((index) => index >= 0 && index < this.xAxisData2.length)
        .map((index) => this.xAxisData2[index]);

      console.log("索引转换结果:", {
        原始索引: indices,
        波长轴长度: this.xAxisData2.length,
        转换后波长: wavelengths,
      });

      return wavelengths;
    },

    genXAxis() {
      return [
        "09:43:00",
        "09:43:10",
        "09:43:20",
        "09:43:30",
        "09:43:40",
        "09:43:50",
        "09:44:00",
      ];
    },
    cancel() {
      this.calibrationdialogVisible = false;
    },

    // 模拟预处理结果
    async simulatePreprocessingResult() {
      if (this.preProcessing_waveData.length === 0) {
        this.$message.warning("请先导入校正集数据");
        return;
      }

      this.preProcessingPayload = {
        preprocessing_sequence: this.methodList
          .filter((item) => item.enabled)
          .map((item) => this.buildMethodPayload(item)),
        wave_data: this.preProcessing_waveData,
      };
      this.pca_req = {
        wave_data: this.preProcessing_waveData,
      };

      console.log("预处理请求数据:", this.preProcessingPayload);

      try {
        const response = await axios.post(
          "/train-model/pretreatment",
          this.preProcessingPayload
        );
        console.log("预处理结果:", response.data);
        this.preProcessing_result = response.data.result;
        console.log(
          "预处理结果: response.data.result",
          this.preProcessing_result
        );
        // 处理返回的预处理数据，更新图表
        if (response.data && response.data.result.X_preprocessed) {
          this.updatePreprocessedChart(response.data.result.X_preprocessed);
        }
      } catch (error) {
        console.error("预处理请求失败:", error);
        this.$message.error(
          "预处理请求失败: " + (error.response?.data?.message || error.message)
        );
      }
    },

    // 波长选择处理
    async handleWavelengthSelection() {
      const selectedMethods = this.wavelengthChooseList.filter(
        (item) => item.enabled
      );

      if (selectedMethods.length === 0) {
        this.$message.warning("请至少选择一种波长选择方法");
        return;
      }

      // 验证所有选中方法的参数
      for (const method of selectedMethods) {
        const requiredParams = method.paramLabels.filter(
          (label) => label !== ""
        );
        for (let i = 0; i < requiredParams.length; i++) {
          if (!method.params[i]) {
            this.$message.error(
              `请填写${method.name}的${requiredParams[i]}参数`
            );
            return;
          }
        }
      }

      // 构建多选方法的payload
      this.trainPayload.wave_select = selectedMethods.map((method) => ({
        root: {
          method: method.method,
          params: this.buildWaveSelectParams(method),
        },
      }));

      console.log("请求数据:", this.trainPayload);
      // this.waveSelect_data = this.trainPayload.wave_select;

      this.$message.success(
        `波长选择参数设置完成，共选择了 ${selectedMethods.length} 种方法`
      );
      this.currentStep = 3;
      this.stepCompleted[3] = true;
      this.wavelengthChooseVisible = false;
    },

    // 模拟波长选择结果
    simulateWavelengthSelection(method) {
      if (this.seriesData2.length === 0) {
        this.$message.warning("请先完成数据预处理");
        return;
      }

      const payload = {
        root: {
          type: item.type, // 如 scaling、smoothing、baseline
          method: item.e_Name, // 如 normalization、sg_smoothing
        },
      };

      // 模拟波长选择后的数据（选择部分波长）
      const selectedSeries = this.seriesData2.map((series) => ({
        ...series,
        data: series.data.filter((_, index) => index % 3 === 0), // 简单模拟：每3个选1个
      }));

      const selectedXAxis = this.xAxisData2.filter(
        (_, index) => index % 3 === 0
      );

      this.seriesData3 = selectedSeries;
      this.xAxisData3 = selectedXAxis;

      console.log("波长选择后的数据:", {
        series: selectedSeries,
        xAxis: selectedXAxis,
      });
    },

    // 处理波长选择结果并更新图表
    processWavelengthSelectionResult(result) {
      if (!result || !result.selected_indices || !result.mask) {
        console.warn("波长选择结果数据格式不正确");
        return;
      }

      console.log("开始处理波长选择结果...");
      console.log("selected_indices:", result.selected_indices);
      console.log("mask:", result.mask);

      // 根据掩码筛选出被选中的波长点
      if (this.xAxisData2 && this.xAxisData2.length > 0) {
        this.chooseWavelength = this.xAxisData2.filter((wavelength, index) => {
          return result.mask[index] === true || result.mask[index] === 1;
        });
        console.log("选择后的波长:", this.chooseWavelength);
      } else {
        // 如果没有预处理的X轴数据，根据掩码生成新的波长数据
        this.chooseWavelength = [];
        result.mask.forEach((isSelected, index) => {
          if (isSelected === true || isSelected === 1) {
            this.chooseWavelength.push(
              (this.startWavelength + index).toString()
            );
          }
        });
        console.log("根据掩码生成的选择后波长:", this.chooseWavelength);
      }

      console.log("波长选择结果已更新:", {
        selectedWavelengths: this.chooseWavelength,
        selectedCount: this.chooseWavelength.length,
      });

      this.$message.success(
        `波长选择完成，共选择了 ${this.chooseWavelength.length} 个波长点`
      );
    },

    // 更新预处理后的图表数据
    updatePreprocessedChart(processedData) {
      if (!processedData || !Array.isArray(processedData)) {
        console.warn("预处理数据格式不正确");
        return;
      }

      const newSeries = [];
      let xAxisSet = new Set();

      processedData.forEach((row, index) => {
        if (Array.isArray(row) && row.length > 1) {
          const [standard, ...wavelengths] = row;
          // 使用 this.startWavelength 作为X轴起点
          const xAxis = wavelengths.map((_, i) =>
            (this.startWavelength + i).toString()
          );
          xAxis.forEach((w) => xAxisSet.add(w));

          newSeries.push({
            name: `Sample ${index + 1}`,
            type: "line",
            data: wavelengths,
          });
        }
      });

      this.seriesData2 = newSeries;
      this.xAxisData2 = Array.from(xAxisSet).sort(
        (a, b) => Number(a) - Number(b)
      );

      console.log("预处理后的图表数据已更新:", {
        series: newSeries,
        xAxis: this.xAxisData2,
      });
    },

    // 显示相关性图
    showCorrelationChart(rowData, latentVariableCount) {
      console.log(
        "点击查看相关性图:",
        rowData,
        "潜在变量数:",
        latentVariableCount
      );

      // 存储当前行数据和潜在变量数
      this.currentRowData = rowData;
      console.log("this.currentRowData:", this.currentRowData);
      this.currentLatentVariableCount = latentVariableCount;

      // 打开对话框
      this.correlationDialogVisible = true;
    },

    // 初始化相关性图表
    initCorrelationChart() {
      if (this.$refs.correlationChart) {
        this.correlationChartInstance = echarts.init(
          this.$refs.correlationChart
        );
        this.drawCorrelationChart();
      }
    },

    // 绘制相关性散点图
    drawCorrelationChart() {
      if (
        !this.correlationChartInstance ||
        !this.best_model_data_history[this.currentLatentVariableCount - 1]
      ) {
        return;
      }

      // 准备数据
      const cvData = [];
      const testData = [];
      const trainData =
        this.best_model_data_history[this.currentLatentVariableCount - 1];

      // CV数据（蓝色点）
      if (trainData.y_cv_true && trainData.y_cv_pred) {
        for (let i = 0; i < trainData.y_cv_true.length; i++) {
          const trueVal = trainData.y_cv_true[i];
          const predVal = trainData.y_cv_pred[i];
          // 处理预测值可能是数组的情况
          const predValue = Array.isArray(predVal) ? predVal[0] : predVal;
          cvData.push([trueVal, predValue]);
        }
      }

      // 验证集数据（红色点）
      if (trainData.test_y && trainData.y_test_pred) {
        for (let i = 0; i < trainData.test_y.length; i++) {
          const trueVal = trainData.test_y[i];
          const predVal = trainData.y_test_pred[i];
          // 处理预测值可能是数组的情况
          const predValue = Array.isArray(predVal) ? predVal[0] : predVal;
          testData.push([trueVal, predValue]);
        }
      }

      // 计算数据范围用于绘制对角线
      const allData = [...cvData, ...testData];
      let minVal = Math.min(
        ...allData.map((point) => Math.min(point[0], point[1]))
      );
      let maxVal = Math.max(
        ...allData.map((point) => Math.max(point[0], point[1]))
      );

      // 扩大范围以便更好地显示
      const padding = (maxVal - minVal) * 0.1;
      minVal -= padding;
      maxVal += padding;

      // 计算回归线函数
      const calcRegression = (data, label) => {
        if (!data || data.length < 2) {
          console.log(`${label} 数据不足，无法计算回归线`);
          return [];
        }
        const n = data.length;
        let sumX = 0,
          sumY = 0,
          sumXY = 0,
          sumXX = 0;
        data.forEach(([x, y]) => {
          sumX += x;
          sumY += y;
          sumXY += x * y;
          sumXX += x * x;
        });
        const denominator = n * sumXX - sumX * sumX;
        if (Math.abs(denominator) < 1e-10) {
          console.log(`${label} 分母接近零，无法计算回归线`);
          return [];
        }
        const slope = (n * sumXY - sumX * sumY) / denominator;
        const intercept = (sumY - slope * sumX) / n;
        const regressionLine = [
          [minVal, slope * minVal + intercept],
          [maxVal, slope * maxVal + intercept],
        ];
        console.log(`${label} 回归线计算成功:`, {
          slope: slope.toFixed(4),
          intercept: intercept.toFixed(4),
        });
        return regressionLine;
      };

      console.log(
        "CV数据数量:",
        cvData.length,
        "Val数据数量:",
        testData.length
      );

      // 图表配置
      const option = {
        title: {
          text: `潜在变量数 ${this.currentLatentVariableCount} 的相关性图`,
          left: "center",
          textStyle: {
            fontSize: 16,
          },
        },
        tooltip: {
          trigger: "item",
          formatter: function (params) {
            if (
              params.seriesName.includes("回归线") ||
              params.seriesName.includes("理想线")
            ) {
              return false; // 不显示回归线和理想线的tooltip
            }
            const type = params.seriesName;
            const [x, y] = params.data;
            return `${type}<br/>真实值: ${x.toFixed(4)}<br/>预测值: ${y.toFixed(
              4
            )}`;
          },
        },
        legend: {
          data: [
            "CV (交叉验证)",
            "Val (验证集)",
            "理想线 (y=x)",
            "CV回归线",
            "Val回归线",
          ],
          top: "8%",
        },
        grid: {
          left: "10%",
          right: "10%",
          bottom: "15%",
          top: "20%",
        },
        xAxis: {
          type: "value",
          name: "真实值 (Reference Value)",
          nameLocation: "center",
          nameGap: 30,
          min: minVal,
          max: maxVal,
        },
        yAxis: {
          type: "value",
          name: "预测值 (Predicted Value)",
          nameLocation: "center",
          nameGap: 50,
          min: minVal,
          max: maxVal,
        },
        series: [
          {
            name: "CV (交叉验证)",
            type: "scatter",
            data: cvData,
            symbolSize: 8,
            itemStyle: { color: "#3498db" },
          },
          {
            name: "Val (验证集)",
            type: "scatter",
            data: testData,
            symbol: "rect",
            symbolSize: 8,
            itemStyle: { color: "#e74c3c" },
          },
          {
            name: "理想线 (y=x)",
            type: "line",
            data: [
              [minVal, minVal],
              [maxVal, maxVal],
            ],
            lineStyle: { color: "#95a5a6", type: "dashed", width: 2 },
            symbol: "none",
          },
          {
            name: "CV回归线",
            type: "line",
            data: calcRegression(cvData, "CV"),
            lineStyle: {
              color: "#3498db",
              type: "dashed",
              width: 2,
              opacity: 0.7,
            },
            symbol: "none",
            silent: true,
          },
          {
            name: "Val回归线",
            type: "line",
            data: calcRegression(testData, "Val"),
            lineStyle: {
              color: "#e74c3c",
              type: "dashed",
              width: 2,
              opacity: 0.7,
            },
            symbol: "none",
            silent: true,
          },
        ],
      };

      this.correlationChartInstance.setOption(option);
    },

    // 销毁图表实例
    destroyCorrelationChart() {
      if (this.correlationChartInstance) {
        this.correlationChartInstance.dispose();
        this.correlationChartInstance = null;
      }
    },
  },
};
</script>

<style scoped>
/* 主容器样式 */
.app-container {
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 固定顶部区域 */
.fixed-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: #fff;
  border-bottom: 1px solid #e4e7ed;
  padding: 10px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* 步骤条样式 */
.steps-container {
  margin-bottom: 15px;
}

/* 防止步骤标题换行 */
.steps-container ::v-deep .el-step__title {
  white-space: nowrap;
  overflow: visible;
  text-overflow: clip;
  max-width: none;
  width: auto;
}

/* 按钮组样式 */
.button-group {
  border: 1px solid #dcdfe6;
  padding: 10px 5px;
  border-radius: 4px;
  background-color: #fafafa;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* 禁用按钮样式 */
.button-group .el-button.is-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* 可滚动内容区域 */
.content-area {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  background-color: #f5f5f5;
}

.modelDataDialog ::v-deep .el-dialog__body {
  padding: 10px;
  max-height: 20vh; /* 控制整个body区域的最大高度 */
  overflow: auto;
}

.dialog-footer {
  /* width: 100%; */
  position: absolute;
  right: 10px;
  bottom: 10px;
}

.ghost {
  opacity: 0.5;
}
.drag-icon {
  cursor: move;
}

.empty-chart-placeholder {
  width: 100%;
  height: 300px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  background-color: #fafafa;
}

.empty-chart-placeholder .chart-title {
  text-align: center;
  font-size: 14px;
  font-weight: bold;
  padding: 10px;
  color: #333;
  border-bottom: 1px solid #ebeef5;
  background-color: #fff;
}

.empty-chart-placeholder .placeholder-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #909399;
}

.empty-chart-placeholder .placeholder-content i {
  font-size: 48px;
  margin-bottom: 16px;
  color: #c0c4cc;
}

.empty-chart-placeholder .placeholder-content p {
  margin: 0;
  font-size: 14px;
}

/* 相关性图链接样式 */
.correlation-link {
  color: #409eff;
  cursor: pointer;
  text-decoration: underline;
  font-size: 14px;
}

.correlation-link:hover {
  color: #66b1ff;
  text-decoration: underline;
}
</style>
